/*
description : LRU缓存设计 2.0 线程安全 + 持久化 + 统计命中
author : chugehehe
time : 2025-2-19
version : 2
*/

#include <iostream>
#include <list>
#include <unordered_map>
#include <optional>
#include <chrono>
#include <mutex>
#include <atomic>
#include <string>
#include <thread>
#include <fstream>
#include <sstream>
#include <vector>
#include <condition_variable>

using std::list;
using std::pair;
using std::unordered_map;
using std::optional;
using std::mutex;
using std::atomic;
using std::string;
using std::thread;
using std::lock_guard;
using std::ifstream;
using std::ofstream;
using std::istringstream;
using std::vector;
using std::condition_variable;

template <typename Key, typename Value, size_t Capacity>
class LRUCache{
    static_assert(Capacity > 0, "Capacity must be positive .");
    // using ListType = list<pair<Key, Value>>; //ver1
    struct CacheItem
    {
        Key key;
        Value value;
        std::chrono::system_clock::time_point last_access;

        // 添加构造函数
        CacheItem(Key k, Value v, std::chrono::system_clock::time_point time)
            : key(std::move(k)), value(std::move(v)), last_access(time) {}
    };
    using ListType = list<CacheItem>; // ver2
private:
    ListType _cacheList;                                       // 缓存链表
    unordered_map<Key, typename ListType::iterator> _cacheMap; // 哈希表存储链表索引
    // unordered_map<Key, ListType::iterator> _cacheMap; // error: ListType::iterator解析依赖于k-v，加typename可以告诉编译器这是一个类型(否则也可能是静态成员)

    mutable mutex _mutex; // 互斥锁 允许const成员函数中修改

    // 统计
    atomic<size_t> _total_opt{0};
    atomic<size_t> _hit_count{0};

    // 持久化
    string _storage_file;
    atomic<bool> running{true};
    thread _auto_save_thread;
    condition_variable _cond;

    static constexpr int AUTO_SAVE_INTERVAL = 60; // 编译时计算constexpr
public:
    explicit LRUCache(const string &filepath)
        : _storage_file(filepath)
    {
        if (!_storage_file.empty())
        {
            loadFromFile();
            startAutoSave();
        }
    }

    ~LRUCache()
    {
        running = false;
        _cond.notify_all();
        if (_auto_save_thread.joinable())
            _auto_save_thread.join();
        if (!_storage_file.empty())
            saveToFile();
    }

    optional<Value> get(const Key &key) // C++17
    {
        lock_guard<mutex> lock(_mutex);
        ++_total_opt; // 操作数

        auto it = _cacheMap.find(key);
        if (it == _cacheMap.end())
            return std::nullopt;

        // 更新链表头 splice(pos, otherList, iterator)
        _cacheList.splice(_cacheList.begin(), _cacheList, it->second);

        // 更新访问时间
        it->second->last_access = std::chrono::system_clock::now();

        ++_hit_count; // 命中
        return it->second->value;
    }

    // 插入元素（完美转发）
    template <typename K, typename V>
    void put(K &&key, V &&value)
    {
        lock_guard<mutex> lock(_mutex);
        auto it = _cacheMap.find(key);
        if (it != _cacheMap.end())
        {
            // 更新链表头
            it->second->value = std::forward<V>(value); // 保持value的右值属性
            _cacheList.splice(_cacheList.begin(), _cacheList, it->second);
            it->second->last_access = std::chrono::system_clock::now();
            return;
        }

        // 容量满-->淘汰尾部
        if (_cacheMap.size() >= Capacity)
        {
            _cacheMap.erase(_cacheList.back().key); // 通过key删除元素
            _cacheList.pop_back();
        }

        // 构造新节点到链表头
        // piecewise_construct用于在构造 std::pair 或 std::tuple 时，将参数分别传递给其成员对象的构造函数
        //  _cacheList.emplace_front(std::piecewise_construct,
        //  std::forward_as_tuple(std::forward<K>(key)), //将参数打包为tuple 保持右值类别
        //  std::forward_as_tuple(std::forward<V>(value)));
        _cacheList.emplace_front(CacheItem{
            std::forward<K>(key),
            std::forward<V>(value),
            std::chrono::system_clock::now()});

        _cacheMap.emplace(std::forward<K>(key), _cacheList.begin());
    }

    // 元素存在性检查
    bool contains(const Key &key) const { return _cacheMap.find(key) != _cacheMap.end(); }

    // 当前缓存大小 承诺不抛出异常
    size_t size() const noexcept { return _cacheMap.size(); }

    // 清空缓存
    void clear() noexcept
    {
        lock_guard<mutex> lock(_mutex);
        _cacheList.clear();
        _cacheMap.clear();
    }

    // 命中率
    double hit_rate() const
    {
        return _total_opt == 0 ? 0.0 : static_cast<double>(_hit_count) / _total_opt;
    }

private:
    void loadFromFile()
    {
        ifstream ifs(_storage_file);
        if (!ifs)
        {
            std::cerr << "open " + _storage_file << " failed.\n";
            return;
        }
        string line;
        vector<CacheItem> items;
        while (std::getline(ifs, line))
        {
            istringstream ss(line);
            Key key;
            Value value;
            long long timestamp;
            if (ss >> key >> value >> timestamp)
            {
                items.emplace_back(
                    std::move(key),
                    std::move(value),
                    std::chrono::system_clock::time_point(std::chrono::nanoseconds(timestamp)));
            }
        }
        lock_guard<mutex> lock(_mutex);
        // 当data文件中不为空时 调用put会导致死锁
        //  for(auto &item : items) put(std::move(item.first), std::move(item.second));
        for (auto &item : items)
        {
            _cacheList.emplace_front(std::move(item));
            _cacheMap.emplace(_cacheList.front().key, _cacheList.begin());
            if (_cacheMap.size() > Capacity) // 淘汰
            {
                _cacheMap.erase(_cacheList.back().key);
                _cacheList.pop_back();
            }
        }
    }

    void saveToFile()
    {
        lock_guard<mutex> lock(_mutex);
        ofstream ofs(_storage_file, std::ios::app);
        if (!ofs)
        {
            std::cerr << "Failed to open file: " << _storage_file << std::endl;
            return;
        }
        for (const auto &item : _cacheList)
        {
            ofs << item.key << " " << item.value << " "
                << item.last_access.time_since_epoch().count() << "\n";
        }
    }

    void startAutoSave()
    {
        _auto_save_thread = thread([this]()
                                   {
            std::cout << "Begin save process....\n";
            std::unique_lock<mutex> lock(_mutex);
            while(running)
            {
                if (_cond.wait_for(lock, std::chrono::seconds(AUTO_SAVE_INTERVAL), [this]() {
                    return !running;
                })) {
                    break;
                }

                lock.unlock();
                saveToFile();
                std::cout << "Auto save process complete.\n";
                lock.lock();
                // std::this_thread::sleep_for(std::chrono::seconds(AUTO_SAVE_INTERVAL));
                // saveToFile();
                // std::cout << "Auto save process complete.\n";
            } });
        std::cout << "Auto save exit.\n";
    }
};
